package com.xlw.service;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SyncResult;
import android.os.Bundle;
import android.util.Log;

import com.tandong.sa.json.JsonParseException;
import com.xlw.api.OnRoadServiceImpl;
import com.xlw.authenticator.AuthenticatorActivity;
import com.xlw.db.DBHelper;
import com.xlw.exception.AndroidOnRoadException;
import com.xlw.model.Trip;
import com.xlw.model.TripDao;

import org.apache.http.ParseException;
import org.apache.http.auth.AuthenticationException;

import java.io.IOException;
import java.util.List;

import static com.xlw.provider.StatusFlag.ADD;
import static com.xlw.provider.StatusFlag.DELETE;
import static com.xlw.provider.StatusFlag.MOD;

/**
 * Created by xinliwei on 2015/7/8.
 *
 * 同步适配器类:
 * 同步适配器是一个由Android平台处理的Service,在这个Service中,可以放置同步代码.
 * 该service通过账户实现与服务器的身份验证,使用ContentProvider同步数据.实现同步适配器后,应用
 * 程序可以自动与服务器同步数据.操作系统将当前同步适配器连同其他同步适配器一起注册到设备中.
 * 同步适配器每次只运行一个,这样可以避免网络阻塞.
 *
 * 同步适配器的优点:
 * 1. 后台自动同步数据(即便并未打开应用程序)
 * 2. 处理服务器身份验证
 * 3. 处理网络重连
 * 4. 遵守用户关于后台同步的偏好设置
 *
 * 该同步适配器需要在AndroidManifest.xml文件中声明.
 *
 * 同步策略可根据自己需要实现
 */
public class OnRoadSyncAdapter extends AbstractThreadedSyncAdapter{

    private static final String TAG = OnRoadSyncAdapter.class.getCanonicalName();

    private final ContentResolver mContentResolver;
    private AccountManager mAccountManager;
    private final static TripDao tripDao = DBHelper.getInstance().tripDao;

    public OnRoadSyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);

        mContentResolver = context.getContentResolver();
        mAccountManager = AccountManager.get(context);
    }

    /**
     * 该方法在后台线程中执行,与服务器同步的逻辑就放在该方法中.
     * @param account   账号
     * @param extras    数据
     * @param authority 认证
     * @param provider  内容提供器
     * @param syncResult 同步结果
     */
    @Override
    public void onPerformSync(Account account, Bundle extras, String authority,
                              ContentProviderClient provider, SyncResult syncResult) {

        String authtoken = null;
        try {
            authtoken = mAccountManager.blockingGetAuthToken(account,
                    AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, true);

            // 从服务器获取所有Trip条目
            List<Trip> data = fetchData();
            // 从本地删除服务器端已经删除的Trip条目
            syncRemoteDeleted(data);
            syncFromServerToLocalStorage(data);
//            syncDirtyToServer(tripDao.getDirtyList(mContentResolver));

        } catch (Exception e) {
            handleException(authtoken, e, syncResult);
        }
    }

    protected void syncDirtyToServer(List<Trip> dirtyList)
            throws AuthenticationException, IOException, AndroidOnRoadException {
        for (Trip trip : dirtyList) {
            Log.d(TAG, "脏数据列表: " + trip);

            switch (trip.getStatusFlag()) {
                case ADD:
                    pushNewTodo(trip);
                    break;
                case MOD:
                    throw new AndroidOnRoadException("不支持修改");
                case DELETE:
                    pushDeleteTodo(trip);
                    break;
                default:
                    throw new RuntimeException("无效的状态: " + trip.getStatusFlag());
            }
        }
    }

    private void pushNewTodo(Trip trip) throws AuthenticationException,
            IOException, AndroidOnRoadException {
        Trip serverTodo = OnRoadServiceImpl.createTrip(trip);
//        tripDao.clearAdd(mContentResolver, trip.getId(), serverTodo);
    }

    private void pushDeleteTodo(Trip trip) throws AuthenticationException, AndroidOnRoadException {
        OnRoadServiceImpl.deleteTrip(trip.getId());
//        tripDao.deleteTodoForced(mContentResolver, trip.getId());
    }

    protected void syncRemoteDeleted(List<Trip> remoteData) {
        Log.d(TAG, "Syncing remote deleted lists...");

//        List<Trip> localClean = tripDao.getCleanTrips(mContentResolver);
//        for (Trip trip : localClean) {
//
//            if (!remoteData.contains(trip)) {
//                Log.d(TAG, "Todo with id " + trip.getId()
//                        + " has been deleted remotely.");
////                tripDao.forcedDeleteTodo(mContentResolver, trip.getId());
//            }
//        }
    }

    protected void syncFromServerToLocalStorage(List<Trip> data) {
        for (Trip tripFromServer : data) {
//            Trip tripInDb = tripDao.isTripInDb(mContentResolver, tripFromServer.getId());

//            if (tripInDb == null) {
//                Log.d(TAG, "从服务器添加新的trip: " + tripFromServer);
//                tripDao.addNewTodo(mContentResolver, tripFromServer, CLEAN);
//
//            } else if (tripInDb.getStatusFlag() == CLEAN) {
//                Log.d(TAG, "从服务器修改列表: " + tripInDb);
//                tripDao.modifyTodoFromServer(mContentResolver, tripFromServer);
//            }

        }
    }

    protected List<Trip> fetchData() throws AuthenticationException,
            AndroidOnRoadException, JsonParseException, IOException {
        List<Trip> list = OnRoadServiceImpl.fetchTrips();

        return list;
    }

    private void handleException(String authtoken, Exception e,
                                 SyncResult syncResult) {
        if (e instanceof AuthenticatorException) {
            syncResult.stats.numParseExceptions++;
            Log.e(TAG, "AuthenticatorException", e);
        } else if (e instanceof OperationCanceledException) {
            Log.e(TAG, "OperationCanceledExcepion", e);
        } else if (e instanceof IOException) {
            Log.e(TAG, "IOException", e);
            syncResult.stats.numIoExceptions++;
        } else if (e instanceof AuthenticationException) {
            mAccountManager.invalidateAuthToken(
                    AuthenticatorActivity.PARAM_ACCOUNT_TYPE, authtoken);
            // The numAuthExceptions require user intervention and are
            // considered hard errors.
            // We automatically get a new hash, so let's make SyncManager retry
            // automatically.
            syncResult.stats.numIoExceptions++;
            Log.e(TAG, "AuthenticationException", e);
        } else if (e instanceof ParseException) {
            syncResult.stats.numParseExceptions++;
            Log.e(TAG, "ParseException", e);
        } else if (e instanceof JsonParseException) {
            syncResult.stats.numParseExceptions++;
            Log.e(TAG, "JSONException", e);
        } else if (e instanceof AndroidOnRoadException) {
            Log.e(TAG, "AndroidOnRoadException", e);
        }
    }
}
